<!-- 可编辑表格 行disabled：false可编辑-->
<template>
  <div>
    <el-table
      v-loading="tableLoading"
      :data="tableData"
      v-bind="tableProps"
      :row-class-name="tableRowClassName"
    >
      <template slot="empty">
        <slot name="empty"></slot>
      </template>
      <el-table-column
        v-if="showIndex"
        type="index"
        label="序号"
      ></el-table-column>
      <el-table-column
        v-for="item in columns.filter(column => !column.hidden)"
        v-bind="item"
        :key="item.prop"
        :show-overflow-tooltip="
          formProps[item.prop] && formProps[item.prop].tooltip
        "
      >
        <template v-slot:header>
          <slot :name="`${item.prop}-header`" :label="item.label">{{
            item.label
          }}</slot>
        </template>
        <template slot-scope="scope">
          <div v-if="!scope.row.disabled && !formProps[item.prop].cantedit">
            <div
              v-if="scope.row.editing && item.prop !== scope.row.disabledColumn"
              :style="getEditBoxStyle(item.align)"
            >
              <!-- input类型 -->
              <el-input
                v-if="formProps[item.prop].type === 'text'"
                v-model="scope.row[item.prop]"
                v-bind="getFormItemProp(item.prop)"
                v-on="methods[item.prop]"
              ></el-input>
              <!-- number类型 -->
              <el-input
                v-if="formProps[item.prop].type === 'number'"
                v-model="scope.row[item.prop]"
                v-bind="getFormItemProp(item.prop)"
                v-on="methods[item.prop]"
                @input="value => formatNumber(scope.row, item.prop, value)"
                @change="
                  value => handleNumberChange(scope.row, item.prop, value)
                "
              ></el-input>
              <!-- integer -->
              <el-input-number
                v-if="formProps[item.prop].type === 'integer'"
                v-model="scope.row[item.prop]"
                v-bind="getFormItemProp(item.prop)"
                v-on="methods[item.prop]"
              ></el-input-number>
              <!-- date-picker -->
              <el-date-picker
                v-if="formProps[item.prop].type === 'date'"
                v-model="scope.row[item.prop]"
                v-bind="getFormItemProp(item.prop)"
                v-on="methods[item.prop]"
                class="w-100"
              >
              </el-date-picker>
              <!-- time-picker -->
              <el-time-picker
                v-if="formProps[item.prop].type === 'time'"
                v-model="scope.row[item.prop]"
                v-bind="getFormItemProp(item.prop)"
                v-on="methods[item.prop]"
                class="w-100"
              >
              </el-time-picker>
              <!-- select类型 -->
              <el-select
                v-if="formProps[item.prop].type === 'select'"
                v-model="scope.row[item.prop]"
                v-bind="getFormItemProp(item.prop)"
                v-on="methods[item.prop]"
                class="w-100"
                filterable
              >
                <el-option
                  v-for="option in formProps[item.prop].options"
                  :key="option.value"
                  :label="option.label"
                  :value="option.value"
                ></el-option>
              </el-select>
              <!-- switch -->
              <el-switch
                v-if="formProps[item.prop].type === 'switch'"
                v-model="scope.row[item.prop]"
                v-bind="getFormItemProp(item.prop)"
                v-on="methods[item.prop]"
              ></el-switch>
              <!-- radio -->
              <el-radio-group
                v-if="formProps[item.prop].type === 'radio'"
                v-model="scope.row[item.prop]"
                v-bind="getFormItemProp(item.prop)"
                v-on="methods[item.prop]"
              >
                <el-radio
                  v-for="option in formProps[item.prop].options"
                  :key="option.value"
                  :label="option.value"
                  >{{ option.label }}</el-radio
                >
              </el-radio-group>
              <!-- checkbox -->
              <el-checkbox-group
                v-if="formProps[item.prop].type === 'checkbox'"
                v-model="scope.row[item.prop]"
                v-bind="getFormItemProp(item.prop)"
                v-on="methods[item.prop]"
              >
                <el-checkbox
                  v-for="option in formProps[item.prop].options"
                  :key="option.value"
                  :label="option.value"
                  >{{ option.label }}</el-checkbox
                >
              </el-checkbox-group>
              <!-- cascader -->
              <el-cascader
                v-if="formProps[item.prop].type === 'cascader'"
                v-model="scope.row[item.prop]"
                v-bind="getFormItemProp(item.prop)"
                v-on="methods[item.prop]"
                class="w-100"
              ></el-cascader>
              <slot
                :name="`${item.prop}_Form`"
                :type="formProps[item.prop].type"
                :options="scope.row['options']"
                :row="scope.row"
              ></slot>
            </div>
            <div v-else>
              <slot
                :name="item.prop"
                :value="scope.row[item.prop]"
                :row="scope.row"
                >{{ scope.row[item.prop] }}</slot
              >
            </div>
          </div>
          <div v-else>
            <slot
              :name="item.prop"
              :row="scope.row"
              :value="scope.row[item.prop]"
              >{{ scope.row[item.prop] }}</slot
            >
          </div>
        </template>
      </el-table-column>
      <el-table-column
        align="center"
        label="操作"
        width="100"
        fixed="right"
        v-if="!disabled"
      >
        <template slot-scope="scope">
          <div v-if="!scope.row.disabled">
            <div v-if="scope.row.editing">
              <el-button
                type="primary"
                icon="el-icon-check"
                :size="tableProps.size"
                plain
                circle
                @click="saveEdit(scope.row)"
              ></el-button>
              <el-button
                type="info"
                icon="el-icon-close"
                :size="tableProps.size"
                plain
                circle
                @click="cancelEdit(scope.row)"
              ></el-button>
            </div>
            <div v-else>
              <el-button
                v-if="showEditButton"
                type="primary"
                icon="el-icon-edit-outline"
                :size="tableProps.size"
                plain
                circle
                @click="editRow(scope.row)"
                :disabled="!isAddable"
              ></el-button>
              <el-button
                v-if="showDeleteButton"
                type="danger"
                icon="el-icon-delete"
                :size="tableProps.size"
                plain
                circle
                @click="removeRow(scope.row)"
                :disabled="!isAddable"
              ></el-button>
            </div>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <el-button
      v-if="showButton"
      type="success"
      plain
      icon="el-icon-plus"
      class="button-add"
      :size="tableProps.size"
      @click="addRow"
      :disabled="!isAddable"
    ></el-button>
  </div>
</template>

<script>
export default {
  name: "editable-grid-old",
  props: {
    // isAddable: {
    //   type: Boolean,
    //   default: true
    // },
    showButton: {
      type: Boolean,
      default: true
    },
    showDeleteButton: {
      type: Boolean,
      default: true
    },
    showEditButton: {
      type: Boolean,
      default: true
    },
    tableProp: {
      type: Object,
      default: () => ({})
    },
    tableLoading: {
      type: Boolean,
      default: false
    },
    columns: {
      type: Array,
      default: () => []
    },
    formProps: {
      type: Object,
      default: () => ({})
    },
    datas: {
      type: Array,
      default: () => []
    },
    methods: {
      type: Object,
      default: () => ({})
    },
    templeteData: {
      type: Object,
      default: () => ({})
    },
    onRowAdd: {
      type: Function
    },
    onRowCancel: {
      type: Function
    },
    onRowDelete: {
      type: Function
    },
    onSwitchEdit: {
      type: Function
    },
    onRowEdit: {
      type: Function
    },
    mode: {
      type: String,
      default: "" // 默认单条保存：""，"cache"为多条保存
    },
    disabled: {
      type: Boolean,
      default: false
    },
    showIndex: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    datas: {
      handler(value, oldvalue) {
        this.$nextTick(() => {
          // if (this.mode === "cache") {
          //   return;
          // }
          this.isAddable = true;
          const copyDatas = JSON.parse(JSON.stringify(value));
          this.tableData = copyDatas.map((item, index) =>
            Object.assign(item, {
              type:
                this.tableData[index] && this.tableData[index].type
                  ? this.tableData[index].type
                  : "",
              editing:
                this.tableData[index] && this.tableData[index].editing
                  ? this.tableData[index].editing
                  : false,
              index
            })
          );
        });
      },
      deep: true
    },
    formProps: {
      handler(value) {
        this.tableData = JSON.parse(JSON.stringify(value));
      }
    }
  },
  data() {
    return {
      tableData: this.datas.map((item, index) =>
        Object.assign({ editing: false, index }, item)
      ),
      tableProps: Object.assign({ border: true, size: "mini" }, this.tableProp),
      isAddable: true
    };
  },
  methods: {
    tableRowClassName(row) {
      if (row.row.invalid) {
        return "hasDeleted";
      }
    },
    getFormItemProp(name) {
      if (this.formProps[name].type === "number") {
        return Object.assign(
          {},
          this.formProps[name],
          { type: "text" },
          { size: this.tableProps.size }
        );
      } else {
        return Object.assign({}, this.formProps[name], {
          size: this.tableProps.size
        });
      }
    },
    formatNumber(row, name, value) {
      const index = this.tableData.findIndex(item => item === row);
      const isMinus = value.charAt(0) === "-";
      const minusMap = { true: "-", false: "" };
      const numberValue = value.replace(/[^0-9.]/g, "");
      const floatValue = parseFloat(minusMap[isMinus] + numberValue);
      if (isNaN(floatValue)) {
        this.tableData[index][name] = "";
        return;
      }
      this.tableData[index][name] = minusMap[isMinus] + numberValue;
      if (numberValue.split(".").length > 2) {
        this.tableData[index][name] =
          minusMap[isMinus] +
          numberValue.split(".")[0] +
          "." +
          numberValue.split(".")[1];
      }
    },
    handleNumberChange(row, name, value) {
      const index = this.tableData.findIndex(item => item === row);
      this.tableData[index][name] = isNaN(parseFloat(value))
        ? 0
        : parseFloat(value);
    },
    editRow(row) {
      if (this.onRowEdit) {
        this.onRowEdit(row);
        this.resetEditState(this.mode);
        const editingRow = Object.assign({}, row, { editing: true });
        this.$set(this.tableData, row.index, editingRow);
      } else {
        this.resetEditState(this.mode);
        const editingRow = Object.assign({}, row, { editing: true });
        this.$set(this.tableData, row.index, editingRow);
        this.onSwitchEdit &&
          typeof this.onSwitchEdit === "function" &&
          this.onSwitchEdit(editingRow);
      }
    },
    removeRow(row) {
      this.$confirm("确定删除本行内容?", "提示", {
        type: "warning"
      })
        .then(() => {
          this.onRowDelete(row)
            .then(res => {
              this.$message({
                type: "success",
                message: "删除成功!"
              });
              this.tableData.splice(row.index, 1);
              this.$set(row, "editing", false);
              this.$emit("changeState", true);
            })
            .catch(reject => {
              this.$message.error(reject);
            });
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消删除"
          });
        });
    },
    saveEdit(row) {
      this.$emit("changeState", true);
      this.onRowAdd(row)
        .then(res => {
          this.mode !== "cache" &&
            this.$message({
              type: "success",
              message: "保存成功!"
            });
          this.$set(
            this.tableData,
            row.index,
            Object.assign({}, res, { editing: false })
          );
        })
        .catch(reject => {
          if (reject) {
            this.$message.error(reject);
          } else {
            this.$message.error("保存失败");
          }
        });
      this.isAddable = true;
    },
    cancelEdit(row) {
      this.onRowCancel && this.onRowCancel(row);
      if (row.id) {
        const data = this.datas.find(item => item.id === row.id);
        this.$set(
          this.tableData,
          row.index,
          Object.assign(row, data, { editing: false })
        );
      } else {
        const index = this.tableData.findIndex(
          item => item.index === row.index
        );
        this.tableData.splice(index, 1);
      }
      this.$emit("changeState", true);
      this.isAddable = true;
    },
    addRow() {
      this.isAddable = false;
      this.resetEditState(this.mode);
      const templete = Object.assign(
        { index: this.tableData.length, editing: true },
        this.templeteData
      );
      this.tableData.push(templete);
      this.$emit("changeState", false);
      this.$emit("isAddable", false);
    },
    getEditBoxStyle(align) {
      const alignMap = {
        left: "flex-start",
        center: "center",
        right: "flex-end"
      };
      return { display: "flex", justifyContent: alignMap[align] };
    },
    resetEditState(mode) {
      this.tableData.map((row, index) => {
        if (mode === "cache") {
          const data = this.datas[index];
          const isEmpty = data
            ? Object.values(data).filter(val => typeof val !== Number && !val)
                .length === data.length
            : true;
          if (!isEmpty) {
            row.editing = false;
          } else {
            const index = this.tableData.findIndex(
              item => item.index === row.index
            );
            this.tableData.splice(index, 1);
          }
        } else {
          if (row.id) {
            row.editing = false;
          } else {
            const index = this.tableData.findIndex(
              item => item.index === row.index
            );
            this.tableData.splice(index, 1);
          }
        }
      });
    }
  }
};
</script>

<style lang="scss" scoped>
.el-icon-delete {
  color: #f56c6c;
  cursor: pointer;
  &:hover {
    color: red;
  }
}
.button-add {
  width: 100%;
  border-style: dashed;
  margin-top: 10px;
  &:hover {
    background: #e7f9dd;
    color: #67c23a;
    font-weight: bold;
  }
}
::v-deep.el-input__inner {
  padding: 0px 2px !important;
}
::v-deep.hasDeleted > td {
  color: #f56c6c;
}
</style>
